#include <linux/module.h>
#include <linux/init.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/of.h>
#include <linux/delay.h>

/*
	mykeys{
		interrupt-parent = <&gpiof>;
		interrupts = <9 0>,<7 0>, <8 0>; 
		interrupts-name = "key1", "key2", "key3";
	};
 */

MODULE_LICENSE("GPL");

typedef struct{
    unsigned int m_irqNumber;
    const char* m_irqName;
}btn_desc_t;
static struct device_node* btnNode;
static btn_desc_t btns[3] = {0};

void btn_work_bottom_half_func(struct work_struct *work)
{
    printk("enter bottom half, do no urgency things...\n");
    msleep(1);
}

DECLARE_WORK(btnWork,btn_work_bottom_half_func);

irqreturn_t btn_irqHandler(int irqNumber, void* dev)
{
    btn_desc_t* data = (btn_desc_t*)dev;
    printk("enter top half, do urgency things...\n");
    printk("%s is pressed!\n",data->m_irqName);
    printk("register bottom half\n");
    schedule_work(&btnWork);
    printk("exit from top half\n");
    return IRQ_HANDLED;
}

static int __init btn_drv_init(void)
{
    int i, ret;
    btnNode = of_find_node_by_path("/mykeys");
    for(i = 0; i < ARRAY_SIZE(btns); i++)
    {
        btns[i].m_irqNumber = irq_of_parse_and_map(btnNode,i);
        of_property_read_string_index(btnNode,"interrupts-name",i,&btns[i].m_irqName);
        ret = request_irq(btns[i].m_irqNumber,btn_irqHandler,IRQF_TRIGGER_FALLING,btns[i].m_irqName,(void*)&btns[i]);
        if(ret<0)
        {
            printk("request_irq is failed by %s\n", btns[i].m_irqName);
            return ret;
        }
    }

    return 0;
}

static void __exit btn_drv_exit(void)
{
    int i;
    for(i=0;i<ARRAY_SIZE(btns);i++)
    {
        free_irq(btns[i].m_irqNumber,(void*)&btns[i]);
    }
}

module_init(btn_drv_init);
module_exit(btn_drv_exit);